package com.gzhryc.shared_device.pcl.code.services;

import com.gzhryc.common.NumberTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.json.JsonTools;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.pay.adaptation.weixin.WXPayNormalPayService;
import com.gzhryc.pay.adaptation.weixin.enums.EWXPayNormalRefundState;
import com.gzhryc.pay.adaptation.weixin.msg.normal.WXPayNormalRefundResponse;
import com.gzhryc.shared_device.base.IDeviceOrderOperateService;
import com.gzhryc.shared_device.base.IMemberWalletService;
import com.gzhryc.shared_device.base.IPayServiceFactory;
import com.gzhryc.shared_device.base.enums.ELogState;
import com.gzhryc.shared_device.base.enums.EOrderOperateState;
import com.gzhryc.shared_device.base.enums.EPayType;
import com.gzhryc.shared_device.base.models.OperateInfo;
import com.gzhryc.shared_device.base.models.OrderLogContent;
import com.gzhryc.shared_device.common.payment.dao.db.WXPayOrder;
import com.gzhryc.shared_device.common.payment.dao.db.WXRefundOrder;
import com.gzhryc.shared_device.common.payment.services.WXPayOrderService;
import com.gzhryc.shared_device.common.payment.services.WXRefundOrderService;
import com.gzhryc.shared_device.pcl.code.dao.PCLOrderDao;
import com.gzhryc.shared_device.pcl.code.dao.db.ChargingCable;
import com.gzhryc.shared_device.pcl.code.dao.db.PCLOrder;
import com.gzhryc.shared_device.pcl.code.dao.enums.PCLOrderEnum;
import com.gzhryc.shared_device.pcl.code.services.dto.PCLOrderSearch;
import com.gzhryc.shared_device.pcl.core.PCLConstants;
import com.gzhryc.shared_device.pcl.core.PwdDecodeFactory;
import com.gzhryc.shared_device.pcl.core.PwdResult;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PCLOrderService implements IDeviceOrderOperateService<PCLOrder> {

    static Logger log = Logger.getLogger(PCLOrderService.class);

    public static PCLOrderService self(Date date) {
        return MultiDBTools.getService(PCLOrderService.class,date);
    }

    public static PCLOrderService self(String jdbcKey,Date date) {
        return MultiDBTools.getService(jdbcKey,PCLOrderService.class, date);
    }

    PCLOrderDao dao;

    public PCLOrderService(String jdbcKey,Date date) {
        dao = new PCLOrderDao(jdbcKey,date);
    }

    public List<PCLOrder> findBySearch(PCLOrderSearch search, Integer pageNo, Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        conditions.and().ge("createDate",search.getCreateStartDate());
        conditions.and().le("createDate",search.getCreateEndDate());
        conditions.and().le("endDate", search.getMaxEndDate());
        conditions.desc("createDate");
        
        try {
            return dao.findByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public Long countBySearch(PCLOrderSearch search){
        Conditions conditions = dao.buildConditions(search);
        conditions.and().ge("createDate",search.getCreateStartDate());
        conditions.and().le("createDate",search.getCreateEndDate());
        conditions.and().le("endDate", search.getMaxEndDate());
        
        try {
            return dao.count(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return 0L;
    }

    public List<PCLOrder> findWorkingByDeviceKeys(String chargingCableSn){
        Conditions conditions = new Conditions(PCLOrder.class);
        conditions.and().is("chargingCableSn",chargingCableSn);
        conditions.and().is("state", PCLOrderEnum.State.Working.index());
        conditions.desc("createDate");

        try {
            return dao.findByCondition(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }

        return null;
    }

    public PCLOrder getNewWorkingByDevice(String chargingCableSn) {
        if (StringTools.isNotBlank(chargingCableSn)) {
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("chargingCableSn", chargingCableSn);
            conditions.and().is("state", PCLOrderEnum.State.Working.index());
            conditions.desc("createDate");
            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public PCLOrder getByTradeNo(String tradeNo){
        if(StringTools.isNotBlank(tradeNo)){
            try {
                return dao.getById(tradeNo);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public boolean updateAgentIdByPlaceId(Long placeId,Long agentId){
        if(placeId != null){
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("placeId",placeId);

            Map<String,Object> map = new HashMap<>();
            map.put("agentId",agentId);

            try {
                return dao.update(map,conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean paySuccess(PCLOrder deviceOrder, OrderLogContent logContent, OperateInfo operateInfo){
        boolean flag = false;

        //设置开始和结束事件
        deviceOrder.setStartDate(new Date());
        deviceOrder.setEndDate(DateUtils.addMinutes(deviceOrder.getStartDate(),deviceOrder.getUseTimes()));

        //计算金额
        Long money = 0L;
        if(deviceOrder.getWalletMoney() == null){
            deviceOrder.setWalletMoney(0L);
        }else {
            money = deviceOrder.getWalletMoney();
        }

        if(deviceOrder.getPayMoney() == null){
            deviceOrder.setPayMoney(0);
        }else{
            money = money + NumberTools.changeMoneyLi(NumberTools.changeMoney(deviceOrder.getPayMoney()));
        }
        deviceOrder.setMoney(money);

        try {
            deviceOrder.setState(PCLOrderEnum.State.CreatePwd.index());
            flag = dao.insert(deviceOrder) > 0;
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        if(flag){
            operateInfo.setOperateNote("支付成功订单入库");
            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder,logContent,operateInfo,ELogState.Success.index(),null);

            //TODO 生成密码
            operateInfo.setOperateNote("生成密码");

            ChargingCable chargingCable = ChargingCableService.self().getByDeviceSn(deviceOrder.getChargingCableSn());
            PwdDecodeFactory.Decoder decoder = PwdDecodeFactory.getDecoder(chargingCable.getProtocolType());
            if(decoder != null){
                PwdResult pwdResult = decoder.getPwd(chargingCable.getDeviceSn(),chargingCable.getSecretKey(),chargingCable.getPwdIndex(),deviceOrder.getSetMealId(),null);
                if(pwdResult != null && pwdResult.isSuccess()){
                    //修改密码
                    PCLOrder updateEntity = new PCLOrder();
                    updateEntity.setTradeNo(deviceOrder.getTradeNo());
                    updateEntity.setPwd(pwdResult.getPwd());
                    updateEntity.setPwdIndex(pwdResult.getIndex());
                    updateEntity.setState(PCLOrderEnum.State.Working.index());
                    updateEntity.setStartDate(new Date());
                    updateEntity.setEndDate(DateUtils.addMinutes(updateEntity.getStartDate(),deviceOrder.getUseTimes()));

                    flag = false;
                    try {
                        if(dao.updateNotNull(updateEntity) > 0){
                            ChargingCableService.self().toWorking(chargingCable.getDeviceSn(), pwdResult.getIndex()
                                    ,deviceOrder.getTradeNo(),deviceOrder.getCreateDate());
                            flag = true;
                        }
                    } catch (SQLException e) {
                        log.error(e.getMessage(),e);
                    }

                    if(flag){
                        PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder,operateInfo,ELogState.Success.index(),null);
                    }else{
                        PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder,operateInfo,ELogState.Fail.index(),"密码写入失败");
                    }
                }else{
                    PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder,operateInfo,ELogState.Fail.index(),"生成密码失败");
                }
            }else{
                PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder,operateInfo,ELogState.Fail.index()
                        ,"未知的密码协议，协议KEY：" + chargingCable.getProtocolType());
            }
            return true;
        }else{
            log.error("新增充电插座订单失败，未触发充电命令，订单信息：{{0:json}}",deviceOrder);
            //TODO 记录入口异常订单
        }
        return false;
    }

    public String changePwd(PCLOrder deviceOrder,OperateInfo operateInfo) throws LogicException {
        if (!PCLOrderEnum.State.Working.index().equals(deviceOrder.getState())) {
            throw new LogicException("订单已结束，不允许切换密码");
        }
        ChargingCable chargingCable = ChargingCableService.self().getByDeviceSn(deviceOrder.getChargingCableSn());
        PwdDecodeFactory.Decoder decoder = PwdDecodeFactory.getDecoder(chargingCable.getProtocolType());
        if(decoder != null) {
            PwdResult pwdResult = decoder.getPwd(chargingCable.getDeviceSn(), chargingCable.getSecretKey(), chargingCable.getPwdIndex(), deviceOrder.getSetMealId(), null);
            if (pwdResult != null && pwdResult.isSuccess()) {
            	Conditions condition = new Conditions(PCLOrder.class);
            	condition.and().is("tradeNo", deviceOrder.getTradeNo());
            	condition.and().is("state", PCLOrderEnum.State.Working.index());
                
            	//修改密码
                PCLOrder updateEntity = new PCLOrder();
                updateEntity.setTradeNo(deviceOrder.getTradeNo());
                updateEntity.setPwd(pwdResult.getPwd());
                updateEntity.setPwdIndex(pwdResult.getIndex());

                boolean flag = false;
                try {
                    if (dao.updateNotNull(updateEntity,condition) > 0) {
                        flag = true;
                    }
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                }

                if (flag) {
                    PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, ELogState.Success.index(), null);
                    //输出密码
                    return pwdResult.getPwd();
                } else {
                    PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, ELogState.Fail.index(), "密码写入失败");
                }
            } else {
                PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, ELogState.Fail.index(), "生成密码失败");
            }
        }
        return null;
    }

    public boolean close(PCLOrder deviceOrder, OperateInfo operateInfo){
        if(deviceOrder != null && StringTools.isNotBlank(deviceOrder.getTradeNo())) {
        	if (PCLOrderEnum.State.Finish.index().equals(deviceOrder.getState()) || PCLOrderEnum.State.Close.index().equals(deviceOrder.getState())) {
        		return true;
        	}
        	
    		Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo", deviceOrder.getTradeNo());
            conditions.and().is("state", deviceOrder.getState());
            
            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setState(PCLOrderEnum.State.Close.index());
            
            try {
                if (dao.updateNotNull(updateEntity, conditions) > 0) {
                    //修改设备状态
                    ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, ELogState.Success.index(), null);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public int refund(PCLOrder deviceOrder, Integer refundMoney, IPayServiceFactory payServiceFactory, OperateInfo operateInfo)throws LogicException {
        if (PCLOrderEnum.PayState.Success.index().equals(deviceOrder.getPayState())) {
            throw new LogicException("支付未成功");
        }

        if(EPayType.WXPay.index().equals(deviceOrder.getPayType())){
            WXPayOrder payOrder = WXPayOrderService.self(deviceOrder.getCreateDate()).getByTradeNo(deviceOrder.getPayTradeNo());
            if (payOrder == null) {
                throw new LogicException("未找到本地微信支付订单");
            }
            WXPayNormalPayService normalPayService = payServiceFactory.getWXPayNormalPayService(payOrder.getAppId(), PCLConstants.BusinessType);
            if (normalPayService == null) {
                throw new LogicException("未找到微信支付服务");
            }
            return refund(deviceOrder,payOrder,refundMoney,normalPayService,operateInfo);
        }else if(EPayType.EWallet.index().equals(deviceOrder.getPayType())){

        }
        return -1;
    }

    private int refund(PCLOrder deviceOrder, WXPayOrder payOrder, Integer refundMoney, WXPayNormalPayService normalPayService,OperateInfo operateInfo) throws LogicException {
        if (deviceOrder.getPayMoney() < refundMoney) {
            throw new LogicException("没有足够的支付金额进行撤销");
        }
        Integer payMoney = deviceOrder.getPayMoney() - refundMoney;
        if (payMoney <= 0) {
            throw new LogicException("退款金额超界");
        }

        Integer operateState = ELogState.Success.index();
        String errorMsg = null;

        if(noOperateTo(deviceOrder.getTradeNo(), EOrderOperateState.Refunding.index())){
            try {
                //触发退款
                WXRefundOrder refundOrder = WXRefundOrderService.self(deviceOrder.getCreateDate()).createRefundOrder(payOrder, refundMoney, operateInfo.getOperateNote());
                WXPayNormalRefundResponse externalResult = normalPayService.applyRefundOrder(refundOrder);
                if (externalResult != null) {
                    if(StringTools.isNotBlank(externalResult.getCode()) && StringTools.isNotBlank(externalResult.getMessage())){
                        operateState = ELogState.Fail.index();
                        errorMsg = externalResult.getMessage();
                    }else if (EWXPayNormalRefundState.SUCCESS.name().equals(externalResult.getStatus())){
                        log.info("{{0}}订单微信直接退款成功，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                    }else if(EWXPayNormalRefundState.CLOSED.name().equals(externalResult.getStatus()) ||
                            EWXPayNormalRefundState.ABNORMAL.name().equals(externalResult.getStatus())) {
                        operateState = ELogState.Fail.index();
                        errorMsg = "退款订单已关闭或异常";
                        log.error("{{0}}订单微信退款失败，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                    }
                } else {
                    operateState = ELogState.Fail.index();
                    errorMsg = "微信退款失败，无响应";
                    log.error("{{0}}订单微信退款失败，无返回信息", payOrder.getTradeNo());
                }
            } catch (Exception e) {
                operateState = ELogState.Fail.index();
                errorMsg = e.getMessage();
                log.error(e.getMessage(), e);
            }finally {
                if (ELogState.Fail.index().equals(operateState)) {
                    //失败回滚数据库
                    faceOperateState(deviceOrder.getTradeNo(), EOrderOperateState.NoOperation.index());
                }
            }
        }else{
            operateState = ELogState.Fail.index();
            errorMsg = "退款时锁定订单失败";
        }

        //增加日志
        PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);
        if(ELogState.Success.index().equals(operateState)) {
            return 1;
        }
        return -1;
    }

    public int cancel(PCLOrder deviceOrder, IPayServiceFactory payServiceFactory,OperateInfo operateInfo) throws LogicException {
        if (PCLOrderEnum.PayState.Cancel.index().equals(deviceOrder.getPayState())) {
            throw new LogicException("设备订单已撤销");
        }

        //关闭设备
        ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());

        if (PCLOrderEnum.PayState.Success.index().equals(deviceOrder.getPayState())) {
            if (EPayType.WXPay.index().equals(deviceOrder.getPayType())) {
                WXPayOrder payOrder = WXPayOrderService.self(deviceOrder.getCreateDate()).getByTradeNo(deviceOrder.getPayTradeNo());
                if (payOrder == null) {
                    throw new LogicException("未找到本地微信支付订单");
                }
                WXPayNormalPayService payService = payServiceFactory.getWXPayNormalPayService(payOrder.getAppId(), PCLConstants.BusinessType);
                if (payService == null) {
                    throw new LogicException("未配置应用支付服务");
                }
                return cancel(deviceOrder, payOrder, payService, operateInfo);
            } else if (EPayType.EWallet.index().equals(deviceOrder.getPayType())) {
                return cancel(deviceOrder, payServiceFactory.getMemberWalletService(), operateInfo);
            }
        }else{
            throw new LogicException("设备订单状态为："+deviceOrder.getPayStateName()+"，无法撤销");
        }
        return -1;
    }

    private int cancel(PCLOrder deviceOrder, WXPayOrder payOrder,WXPayNormalPayService payService,OperateInfo operateInfo) throws LogicException {
        if(EOrderOperateState.NoOperation.index().equals(deviceOrder.getOperateState()) && StringTools.isNotBlank(deviceOrder.getTradeNo())) {
            Integer refundMoney = deviceOrder.getPayMoney();
            Integer operateState = ELogState.Success.index();
            String errorMsg = null;

            if (refundMoney > 0) {
                if(noOperateTo(deviceOrder.getTradeNo(),EOrderOperateState.Cancelling.index())) {
                    //触发退款
                    try {
                        WXRefundOrder refundOrder = WXRefundOrderService.self(deviceOrder.getCreateDate()).createRefundOrder(payOrder, refundMoney, operateInfo.getOperateNote());
                        if (refundOrder != null) {
                            WXPayNormalRefundResponse externalResult = payService.applyRefundOrder(refundOrder);
                            if (externalResult != null) {
                                if(StringTools.isNotBlank(externalResult.getCode()) && StringTools.isNotBlank(externalResult.getMessage())){
                                    operateState = ELogState.Fail.index();
                                    errorMsg = externalResult.getMessage();
                                }else if (EWXPayNormalRefundState.SUCCESS.name().equals(externalResult.getStatus())){
                                    log.info("{{0}}订单微信直接退款成功，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                                }else if(EWXPayNormalRefundState.CLOSED.name().equals(externalResult.getStatus()) ||
                                        EWXPayNormalRefundState.ABNORMAL.name().equals(externalResult.getStatus())) {
                                    operateState = ELogState.Fail.index();
                                    errorMsg = "退款订单已关闭或异常";
                                    log.error("{{0}}订单微信退款失败，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                                }
                            } else {
                                operateState = ELogState.Fail.index();
                                errorMsg = "微信退款失败，无响应";
                                log.error("{{0}}订单微信退款失败，无返回信息", payOrder.getTradeNo());
                            }
                        } else {
                            operateState = ELogState.Fail.index();
                            errorMsg = "创建微信退款订单失败";
                        }
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        operateState = ELogState.Fail.index();
                        errorMsg = e.getMessage();
                    }finally {
                        if (ELogState.Fail.index().equals(operateState)) {
                            //失败回滚数据库
                            faceOperateState(deviceOrder.getTradeNo(), EOrderOperateState.NoOperation.index());
                        }
                    }
                }else {
                    operateState = ELogState.Fail.index();
                    errorMsg = "退款时锁定订单失败";
                }

                //记录日志
                operateInfo.setOperateNote("【撤销订单】" + operateInfo.getOperateNote());
                PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);
                if (ELogState.Success.index().equals(operateState)) {
                    return 1;
                }
            } else {
                try {
                    Conditions conditions = new Conditions(PCLOrder.class);
                    conditions.and().is("tradeNo", deviceOrder.getTradeNo());
                    conditions.and().is("operateState", deviceOrder.getOperateState());
                    conditions.and().is("state", deviceOrder.getState());

                    PCLOrder updateEntity = new PCLOrder();
                    updateEntity.setTradeNo(deviceOrder.getTradeNo());
                    updateEntity.setMoney(0L);      //强制修改
                    updateEntity.setPayMoney(0);
                    updateEntity.setPayState(PCLOrderEnum.PayState.Cancel.index());
                    //非终结状态，则修改为失败状态
                    if (PCLOrderEnum.State.WaitStart.index().equals(deviceOrder.getState()) || PCLOrderEnum.State.Working.index().equals(deviceOrder.getState())) {
                        updateEntity.setState(PCLOrderEnum.State.Close.index());
                    }

                    if (dao.updateNotNull(updateEntity,conditions) > 0) {
                        deviceOrder.setState(updateEntity.getState());
                        //修改设备状态
                        ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    }else{
                        operateState = ELogState.Fail.index();
                        errorMsg = "修改数据库失败";
                    }
                } catch (SQLException e) {
                    operateState = ELogState.Fail.index();
                    errorMsg = e.getMessage();
                    log.error(e.getMessage(), e);
                }

                //记录日志
                operateInfo.setOperateNote("【撤销订单】" + operateInfo.getOperateNote());
                PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);

                if (ELogState.Success.index().equals(operateState)) {
                    return 2;
                }
            }
        }
        return -1;
    }

    private int cancel(PCLOrder deviceOrder, IMemberWalletService memberWalletService, OperateInfo operateInfo)throws LogicException {
        if(EOrderOperateState.NoOperation.index().equals(deviceOrder.getOperateState()) && StringTools.isNotBlank(deviceOrder.getTradeNo())) {
            Long refundMoney = deviceOrder.getWalletMoney();

            Integer operateState = ELogState.Success.index();
            String errorMsg = null;

            JdbcSession.begin();
            try {
                Conditions conditions = new Conditions(PCLOrder.class);
                conditions.and().is("tradeNo", deviceOrder.getTradeNo());
                conditions.and().is("operateState", deviceOrder.getOperateState());
                conditions.and().is("state", deviceOrder.getState());

                PCLOrder updateEntity = new PCLOrder();
                updateEntity.setMoney(0L);
                updateEntity.setWalletMoney(0L);
                updateEntity.setPayState(PCLOrderEnum.PayState.Cancel.index());
                updateEntity.setCancelDate(new Date());

                //非终结状态，则修改为失败状态
                if (PCLOrderEnum.State.WaitStart.index().equals(deviceOrder.getState()) || PCLOrderEnum.State.Working.index().equals(deviceOrder.getState())) {
                    updateEntity.setState(PCLOrderEnum.State.Close.index());
                }

                if (dao.updateNotNull(updateEntity,conditions) > 0) {
                    //修改设备状态
                    ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    if (refundMoney > 0) {
                        if (memberWalletService.addMoney(deviceOrder.getMemberId(), refundMoney, operateInfo)) {
                            deviceOrder.setState(updateEntity.getState());
                            JdbcSession.commit();
                        } else {
                            operateState = ELogState.Fail.index();
                            errorMsg = "新增会员钱包余额失败";
                        }
                    } else {
                        deviceOrder.setState(updateEntity.getState());
                        JdbcSession.commit();
                    }
                } else {
                    operateState = ELogState.Fail.index();
                    errorMsg = "修改设备订单失败";
                }
            } catch (SQLException e) {
                operateState = ELogState.Fail.index();
                errorMsg = e.getMessage();
                log.error(e.getMessage(), e);
            } finally {
                JdbcSession.end();
            }

            //记录日志
            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);
            if (ELogState.Success.index().equals(operateState)) {
                return 2;
            }
        }
        return -1;
    }

    /**
     * 完成订单，包括系统定时结束，手动结束
     * return -1:系统错误，1:退款中，2:已处理
     */
    public int finish(PCLOrder deviceOrder, Integer payMoney, IPayServiceFactory payServiceFactory,OperateInfo operateInfo) throws LogicException {
        if (PCLOrderEnum.State.Finish.index().equals(deviceOrder.getState()) || PCLOrderEnum.State.Close.index().equals(deviceOrder.getState())) {
            throw new LogicException("设备订单已完成");
        }

        //关闭设备
        ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
        
        if(EPayType.WXPay.index().equals(deviceOrder.getPayType())){
            WXPayOrder payOrder = WXPayOrderService.self(deviceOrder.getCreateDate()).getByTradeNo(deviceOrder.getPayTradeNo());
            if (payOrder == null) {
                throw new LogicException("未找到本地微信支付订单");
            }
            WXPayNormalPayService payService = payServiceFactory.getWXPayNormalPayService(payOrder.getAppId(), PCLConstants.BusinessType);
            if (payService == null) {
                throw new LogicException("未配置应用支付服务");
            }
            return finish(deviceOrder,payOrder,payMoney,payService,operateInfo);
        }else if(EPayType.EWallet.index().equals(deviceOrder.getPayType())){
            Long walletMoney = NumberTools.changeMoneyLi(NumberTools.changeMoney(payMoney));
            return finish(deviceOrder,walletMoney,payServiceFactory.getMemberWalletService(),operateInfo);
        }
        return -1;
    }

    private int finish(PCLOrder deviceOrder, WXPayOrder payOrder,Integer payMoney, WXPayNormalPayService payService,OperateInfo operateInfo) throws LogicException {
        if (EOrderOperateState.NoOperation.index().equals(deviceOrder.getOperateState())) {
            Integer refundMoney = 0;
            if (payOrder.getPayMoney() < payMoney) {
                throw new LogicException("客户支付金额小于结算金额，订单无法完成");
            } else if (payOrder.getPayMoney() > payMoney) {
                //单位转化，厘变分
                refundMoney = payOrder.getPayMoney() - payMoney;
            }

            Integer operateState = ELogState.Success.index();
            String errorMsg = null;

            Long money = NumberTools.changeMoneyLi(NumberTools.changeMoney(payMoney));

            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo", deviceOrder.getTradeNo());
            conditions.and().is("operateState", deviceOrder.getOperateState());
            conditions.and().is("state", deviceOrder.getState());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setMoney(money);
            updateEntity.setPayMoney(payMoney);
            updateEntity.setState(PCLOrderEnum.State.Finish.index());
            updateEntity.setFinishDate(new Date());

            try {
                if (dao.updateNotNull(updateEntity,conditions) <= 0) {
                    operateState = ELogState.Fail.index();
                    errorMsg = "修改数据库失败";
                }
            } catch (SQLException e) {
                operateState = ELogState.Fail.index();
                errorMsg = e.getMessage();
                log.error(e.getMessage(), e);
            }

            //记录日志
            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);

            if (ELogState.Success.index().equals(operateState)) {
                if (refundMoney > 0) {
                    if (noOperateTo(deviceOrder.getTradeNo(), EOrderOperateState.Finishing.index())) {
                        try {
                            //触发退款
                            WXRefundOrder refundOrder = WXRefundOrderService.self(deviceOrder.getCreateDate()).createRefundOrder(payOrder, refundMoney, operateInfo.getOperateNote());
                            WXPayNormalRefundResponse externalResult = payService.applyRefundOrder(refundOrder);
                            if (externalResult != null) {
                                if (StringTools.isNotBlank(externalResult.getCode()) && StringTools.isNotBlank(externalResult.getMessage())) {
                                    operateState = ELogState.Fail.index();
                                    errorMsg = externalResult.getMessage();
                                } else if (EWXPayNormalRefundState.SUCCESS.name().equals(externalResult.getStatus())) {
                                    log.info("{{0}}订单微信直接退款成功，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                                } else if (EWXPayNormalRefundState.CLOSED.name().equals(externalResult.getStatus()) ||
                                        EWXPayNormalRefundState.ABNORMAL.name().equals(externalResult.getStatus())) {
                                    operateState = ELogState.Fail.index();
                                    errorMsg = "退款订单已关闭或异常";
                                    log.error("{{0}}订单微信退款失败，返回信息：{{1}}", payOrder.getTradeNo(), JsonTools.toJson(externalResult));
                                }
                            } else {
                                operateState = ELogState.Fail.index();
                                errorMsg = "微信退款失败，无响应";
                                log.error("{{0}}订单微信退款失败，无返回信息", payOrder.getTradeNo());
                            }
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                            operateState = ELogState.Fail.index();
                            errorMsg = e.getMessage();
                        } finally {
                            if (ELogState.Fail.index().equals(operateState)) {
                                //失败回滚数据库
                                faceOperateState(deviceOrder.getTradeNo(), EOrderOperateState.NoOperation.index());
                            }
                        }
                    } else {
                        operateState = ELogState.Fail.index();
                        errorMsg = "完成时锁定订单失败";
                    }
                    //记录日志
                    operateInfo.setOperateNote("第三方订单退款");
                    PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);
                }
            }

            if (ELogState.Success.index().equals(operateState)) {
                if (refundMoney > 0) {
                    return 1;
                }else{
                    return 2;
                }
            }
        }
        return -1;
    }

    private int finish(PCLOrder deviceOrder, Long walletMoney, IMemberWalletService memberWalletService, OperateInfo operateInfo) throws LogicException {
        if(EOrderOperateState.NoOperation.index().equals(deviceOrder.getOperateState()) && StringTools.isNotBlank(deviceOrder.getTradeNo())) {
            Long refundMoney = 0L;
            if (deviceOrder.getWalletMoney() < walletMoney) {
                throw new LogicException("客户支付金额小于结算金额，订单无法完成");
            } else if (deviceOrder.getWalletMoney() > walletMoney) {
                refundMoney = deviceOrder.getWalletMoney() - walletMoney;
            }

            Integer operateState = ELogState.Success.index();
            String errorMsg = null;

            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo", deviceOrder.getTradeNo());
            conditions.and().is("operateState", deviceOrder.getOperateState());
            conditions.and().is("state", deviceOrder.getState());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setMoney(walletMoney);
            updateEntity.setWalletMoney(walletMoney);
            updateEntity.setState(PCLOrderEnum.State.Finish.index());
            updateEntity.setFinishDate(new Date());

            JdbcSession.begin();
            try {
                if (dao.updateNotNull(updateEntity,conditions) > 0) {
                    if(refundMoney > 0) {
                        if (memberWalletService.addMoney(deviceOrder.getMemberId(), refundMoney, operateInfo)) {
                            JdbcSession.commit();
                        } else {
                            operateState = ELogState.Fail.index();
                            errorMsg = "修改会员余额失败";
                        }
                    }else{
                        JdbcSession.commit();
                    }
                }else{
                    operateState = ELogState.Fail.index();
                    errorMsg = "修改订单表失败";
                }
            } catch (SQLException e) {
                operateState = ELogState.Fail.index();
                errorMsg = e.getMessage();
                log.error(e.getMessage(), e);
            }finally {
                JdbcSession.end();
            }

            //记录日志
            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);
            if (ELogState.Success.index().equals(operateState)) {
                return 2;
            }
        }
        return -1;
    }

    public int refundSuccess(WXRefundOrder refundOrder,OperateInfo operateInfo){
        PCLOrder deviceOrder = getByTradeNo(refundOrder.getBusinessTradeNo());
        if(deviceOrder == null){
            log.error("退款成功，未找到设备订单，退款订单信息：{{0:json}}",refundOrder);
        }
        if(EOrderOperateState.Cancelling.index().equals(deviceOrder.getOperateState())){
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo",refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState",EOrderOperateState.Cancelling.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());
            updateEntity.setPayState(PCLOrderEnum.PayState.Cancel.index());
            updateEntity.setMoney(0L);
            updateEntity.setPayMoney(0);
            updateEntity.setCancelDate(new Date());

            Integer logState = ELogState.Fail.index();
            String errorMsg = "修改订单状态失败";
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    //修改设备状态
                    ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    logState = ELogState.Success.index();
                    errorMsg = null;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
                errorMsg = e.getMessage();
            }

            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, logState, errorMsg);
            if(ELogState.Success.index().equals(logState)){
                return 1;
            }
        }else if(EOrderOperateState.Finishing.index().equals(deviceOrder.getOperateState())){
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo",refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState",EOrderOperateState.Finishing.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());
            updateEntity.setPayState(PCLOrderEnum.PayState.Success.index());

            Integer logState = ELogState.Fail.index();
            String errorMsg = "修改订单状态失败";
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    //修改设备状态
                    ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    logState = ELogState.Success.index();
                    errorMsg = null;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }

            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, logState, errorMsg);
            if(ELogState.Success.index().equals(logState)){
                return 3;
            }
        }else if(EOrderOperateState.Refunding.index().equals(deviceOrder.getOperateState())){
            //计算具体金额
            Integer payMoney = deviceOrder.getPayMoney() - refundOrder.getRefundMoney();
            if(payMoney < 0){
                payMoney = 0;
            }
            Long money = NumberTools.changeMoneyLi(NumberTools.changeMoney(payMoney));

            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo",refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState",EOrderOperateState.Refunding.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());
            updateEntity.setPayState(PCLOrderEnum.PayState.Success.index());
            updateEntity.setMoney(money);
            updateEntity.setPayMoney(payMoney);
            updateEntity.setFinishDate(new Date());

            Integer logState = ELogState.Fail.index();
            String errorMsg = "修改订单状态失败";
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    //修改设备状态
                    ChargingCableService.self().toFree(deviceOrder.getChargingCableSn());
                    logState = ELogState.Success.index();
                    errorMsg = null;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }

            PCLOrderLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, logState, errorMsg);
            if(ELogState.Success.index().equals(logState)){
                return 2;
            }
        }
        return -1;
    }

    public boolean refundFail(WXRefundOrder refundOrder,OperateInfo operateInfo){
        PCLOrder deviceOrder = getByTradeNo(refundOrder.getBusinessTradeNo());
        if(deviceOrder == null){
            log.error("退款失败，未找到设备订单，退款订单信息：{{0:json}}",refundOrder);
        }

        if(EOrderOperateState.Cancelling.index().equals(deviceOrder.getOperateState())){
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo",refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState",EOrderOperateState.Cancelling.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }else if(EOrderOperateState.Refunding.index().equals(deviceOrder.getOperateState())) {
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo", refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState", EOrderOperateState.Refunding.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());
            try {
                if (dao.updateNotNull(updateEntity, conditions) > 0) {
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }else if(EOrderOperateState.Finishing.index().equals(deviceOrder.getOperateState())) {
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo", refundOrder.getBusinessTradeNo());
            conditions.and().is("operateState", EOrderOperateState.Finishing.index());

            PCLOrder updateEntity = new PCLOrder();
            updateEntity.setOperateState(EOrderOperateState.NoOperation.index());

            try {
                if (dao.updateNotNull(updateEntity, conditions) > 0) {
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean noOperateTo(String tradeNo,Integer operateState){
        if(StringTools.isNotBlank(tradeNo) && operateState != null){
            Conditions conditions = new Conditions(PCLOrder.class);
            conditions.and().is("tradeNo",tradeNo);
            conditions.and().is("operateState",EOrderOperateState.NoOperation.index());

            PCLOrder deviceOrder = new PCLOrder();
            deviceOrder.setOperateState(operateState);

            try {
                return dao.updateNotNull(deviceOrder,conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean faceOperateState(String tradeNo,Integer operateState){
        if(StringTools.isNotBlank(tradeNo) && operateState != null){
            PCLOrder deviceOrder = new PCLOrder();
            deviceOrder.setTradeNo(tradeNo);
            deviceOrder.setOperateState(operateState);

            try {
                return dao.updateNotNull(deviceOrder) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }
}
